﻿Imports System.Xml
Imports System.Security.Cryptography
Imports System.IO

Public Class AppSettings
    Private m_Server As String
    Private m_Port As Integer
    Private m_Username As String
    Private m_Password As String
    Private m_MailboxName As String
    Private m_DoTracing As Boolean
    Private m_TraceFileLocation As String
    Private m_Refresh As Integer
    Private m_SpecificConnection As Integer

    ''' <summary>
    ''' The IMAP Server to connect to.
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Server() As String
        Get
            Return m_Server
        End Get
        Set(ByVal value As String)
            m_Server = value
        End Set
    End Property

    ''' <summary>
    ''' The port of the IMAP server to connect to.
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Port() As Integer
        Get
            Return m_Port
        End Get
        Set(ByVal value As Integer)
            m_Port = value
        End Set
    End Property

    ''' <summary>
    ''' The username to provide to the imap server
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Username() As String
        Get
            Return m_Username
        End Get
        Set(ByVal value As String)
            m_Username = value
        End Set
    End Property

    ''' <summary>
    ''' The password to provide to the imap server
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Password() As String
        Get
            Return m_Password
        End Get
        Set(ByVal value As String)
            m_Password = value
        End Set
    End Property

    ''' <summary>
    ''' The mailboxname to provide to the imap server
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property MailboxName() As String
        Get
            Return m_MailboxName
        End Get
        Set(ByVal value As String)
            m_MailboxName = value
        End Set
    End Property

    ''' <summary>
    ''' Should we trace output to a file?
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property DoTracing() As Boolean
        Get
            Return m_DoTracing
        End Get
        Set(ByVal value As Boolean)
            m_DoTracing = value
        End Set
    End Property

    ''' <summary>
    ''' The location of the file to use for tracing.
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property TraceFileLocation() As String
        Get
            Return m_TraceFileLocation
        End Get
        Set(ByVal value As String)
            m_TraceFileLocation = value
        End Set
    End Property

    Public Property Refresh() As Integer
        Get
            Return m_Refresh
        End Get
        Set(ByVal value As Integer)
            m_Refresh = value
        End Set
    End Property

    Public Property SpecificConnection() As Integer
        Get
            Return m_SpecificConnection
        End Get
        Set(ByVal value As Integer)
            m_SpecificConnection = value
        End Set
    End Property

    Public ReadOnly Property UseSpecific() As Boolean
        Get
            Return SpecificConnection <> -1
        End Get
    End Property

    

    Private m_IV As Byte() = {79, 174, 106, 93, 88, 44, 134, 244, 40, 182, 82, 187, 202, 164, 98, 119}
    Private m_Key As Byte() = {75, 25, 222, 62, 230, 169, 103, 131, 170, 78, 113, 101, 67, 74, 122, 168, 24, 219, 0, 192, 118, 149, 26, 145, 244, 83, 220, 206, 149, 80, 3, 168}

    Public Function EncryptPassword(ByVal pPass As String) As String
        Dim _rj As Rijndael = RijndaelManaged.Create()
        _rj.IV = m_IV
        _rj.Key = m_Key

        Dim _encryptor As ICryptoTransform = _rj.CreateEncryptor(m_Key, m_IV)

        Dim _ms As New MemoryStream
        Dim _cs As New CryptoStream(_ms, _encryptor, CryptoStreamMode.Write)

        Dim _Ascii As New Text.ASCIIEncoding
        Dim _bytes As Byte() = _Ascii.GetBytes(pPass)

        _cs.Write(_bytes, 0, _bytes.Length)
        _cs.FlushFinalBlock()

        Dim _encrypted As Byte() = _ms.ToArray
        Return System.Convert.ToBase64String(_encrypted)
    End Function

    Public Function DecryptPassword(ByVal pPassword As String) As String
        Dim _rj As Rijndael = RijndaelManaged.Create()
        _rj.IV = m_IV
        _rj.Key = m_Key

        Dim _decryptor As ICryptoTransform = _rj.CreateDecryptor(m_Key, m_IV)
        Dim _encrypted As Byte() = System.Convert.FromBase64String(pPassword)
        Dim _ms As New MemoryStream(_encrypted)
        Dim _cs As New CryptoStream(_ms, _decryptor, CryptoStreamMode.Read)

        Dim _decrypted(_encrypted.Length) As Byte
        Dim _bytes As Integer = _cs.Read(_decrypted, 0, _decrypted.Length)
        Dim _Ascii As New Text.ASCIIEncoding
        Dim _str As String = _Ascii.GetString(_decrypted, 0, _bytes)
        Return _str
    End Function

    Public Sub Save(ByVal pEle As XmlElement)
        pEle.SetAttribute("Server", m_Server)
        pEle.SetAttribute("Port", m_Port.ToString)
        pEle.SetAttribute("Username", m_Username)
        pEle.SetAttribute("Password", EncryptPassword(m_Password))
        pEle.SetAttribute("MailboxName", m_MailboxName)
        pEle.SetAttribute("DoTracing", m_DoTracing.ToString)
        pEle.SetAttribute("TraceFileLocation", m_TraceFileLocation)
        pEle.SetAttribute("Refresh", m_Refresh.ToString)
        pEle.SetAttribute("SpecificConnection", m_SpecificConnection.ToString)
    End Sub

    Public Sub Load(ByVal pEle As XmlElement)
        m_Server = pEle.GetAttribute("Server")
        m_Port = Integer.Parse(pEle.GetAttribute("Port"))
        m_Username = pEle.GetAttribute("Username")
        m_Password = DecryptPassword(pEle.GetAttribute("Password"))
        m_MailboxName = pEle.GetAttribute("MailboxName")
        m_DoTracing = Boolean.Parse(pEle.GetAttribute("DoTracing"))
        m_TraceFileLocation = pEle.GetAttribute("TraceFileLocation")
        m_Refresh = Integer.Parse(pEle.GetAttribute("Refresh"))
        m_SpecificConnection = Integer.Parse(pEle.GetAttribute("SpecificConnection"))
    End Sub
End Class

Public Class AppSettingsCollection
    Private m_AppSettings As New Generic.Dictionary(Of String, AppSettings)
    Private m_TraceFileLocation As String
    Private m_StatusPort As Integer = -1
    
    Public ReadOnly Property DoTracing() As Boolean
        Get
            Return Not String.IsNullOrEmpty(m_TraceFileLocation)
        End Get
    End Property
    Public Property StatusPort() As Integer
        Get
            Return m_StatusPort
        End Get
        Set(ByVal value As Integer)
            m_StatusPort = value
        End Set
    End Property

    Public Property TraceFileLocation() As String
        Get
            Return m_TraceFileLocation
        End Get
        Set(ByVal value As String)
            m_TraceFileLocation = value
        End Set
    End Property

    Public Property Settings() As Generic.Dictionary(Of String, AppSettings)
        Get
            Return m_AppSettings
        End Get
        Set(ByVal value As Generic.Dictionary(Of String, AppSettings))
            m_AppSettings = value
        End Set
    End Property

    Public Function GetFileName() As String
        Dim _path As String = System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
        _path = IO.Path.Combine(_path, "ImapPusher")
        If Not IO.Directory.Exists(_path) Then
            IO.Directory.CreateDirectory(_path)
        End If
        _path = IO.Path.Combine(_path, "Settings.xml")

        Return _path
    End Function

    Public Sub New()
        Dim _f As String = GetFileName()
        If Not File.Exists(_f) Then
            Exit Sub
        End If
        Dim _xmlDoc As New XmlDocument
        _xmlDoc.Load(_f)

        Dim _settings As XmlElement = CType(_xmlDoc.FirstChild, XmlElement)
        m_TraceFileLocation = _settings.GetAttribute("TraceFileLocation")
        Dim _statusPortString As String = _settings.GetAttribute("StatusPort")
        If Not String.IsNullOrEmpty(_statusPortString) Then
            m_StatusPort = Integer.Parse(_statusPortString)
        End If
        Dim _autoStartString As String = _settings.GetAttribute("AutoStart")
        
        If _settings.Name <> "Settings" Then
            Exit Sub
        End If
        For Each _setting As XmlElement In _settings.ChildNodes
            Dim _appSetting As New AppSettings()
            _appSetting.Load(_setting)
            m_AppSettings.Add(_appSetting.MailboxName, _appSetting)
        Next
    End Sub

    Public Sub Save()
        Dim _f As String = GetFileName()
        If File.Exists(_f) Then File.Delete(_f)
        Dim _xmlDoc As New XmlDocument
        Dim _root As XmlElement = _xmlDoc.CreateElement("Settings")
        If m_TraceFileLocation IsNot Nothing Then _root.SetAttribute("TraceFileLocation", m_TraceFileLocation)
        If m_StatusPort <> -1 Then _root.SetAttribute("StatusPort", m_StatusPort.ToString)
        
        _xmlDoc.AppendChild(_root)
        For Each _appSetting As AppSettings In m_AppSettings.Values
            Dim _setting As XmlElement = _xmlDoc.CreateElement("AppSettings")
            _appSetting.Save(_setting)
            _root.AppendChild(_setting)
        Next
        _xmlDoc.Save(_f)
    End Sub
End Class